package com.example.aiscripteditorserver.common.tools.match;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.springframework.util.StreamUtils;

@Slf4j
public class ImgMatcherUtils {

    public static MatchResult multiScaleMatch(Mat bigImage,
                                              Mat smallImage,
                                              String saveResultPath,
                                              double startScale,
                                              double endScale,
                                              double step,
                                              double threshold) {

        MatchResult bestMatch = null;

        try {
            // 4. 执行多尺度模板匹配，获取最佳匹配结果
            bestMatch = findBestMatch(
                    bigImage, smallImage, startScale, endScale, step, threshold
            );

            // 5. 处理匹配结果（标记区域 + 保存图片）
            if (bestMatch != null) {
                // 打印匹配信息
                System.out.println("=== 匹配成功 ===");
                System.out.println("匹配位置：(" + bestMatch.getStartPoint().x + ", " + bestMatch.getStartPoint().y + ")");
                System.out.println("匹配区域大小：" + bestMatch.getWidth() + "x" + bestMatch.getHeight());
                System.out.println("缩放比例：" + String.format("%.2f", bestMatch.getScale()));
                System.out.println("匹配度：" + String.format("%.4f", bestMatch.getMatching()));
                // System.out.println("结果图片将保存至：" + new File(saveResultPath).getAbsolutePath());

                // 在大图上绘制绿色矩形框，标记匹配区域（边框厚度2px）
                Imgproc.rectangle(
                        bigImage,
                        bestMatch.getStartPoint(),
                        bestMatch.getEndPoint(),
                        new Scalar(0, 255, 0), // 颜色：绿色（OpenCV中颜色格式为BGR）
                        2 // 边框厚度
                );

                // 保存标记后的结果图片到本地
                String savedPath = StringUtils.isNotEmpty(saveResultPath) ? saveResultPath : "success_result.png";
                boolean saveSuccess = Imgcodecs.imwrite(savedPath, bigImage);
                if (saveSuccess) {
                    System.out.println("结果图片保存成功！");
                } else {
                    System.out.println("警告：结果图片保存失败，请检查路径是否有写入权限！");
                }

                // 显示匹配结果（弹窗预览）
                /*HighGui.imshow("多尺度模板匹配结果", sourceImage);
                System.out.println("提示：关闭预览窗口即可结束程序。");
                HighGui.waitKey(0); // 等待用户关闭窗口
                HighGui.destroyAllWindows();*/

            } else {
                System.out.println("=== 匹配失败 ===");
                System.out.println("在 [" + startScale + "~" + endScale + "] 缩放范围内，未找到匹配度高于 " + threshold + " 的区域。");
                // 可选：保存原始截图（无标记）用于调试
                Imgcodecs.imwrite("error_source.png", bigImage);
                Imgcodecs.imwrite("error_temp.png", smallImage);
                System.out.println("已保存匹配失败 目标图/原始屏幕截图 至：error_temp.png/error_source.png");
            }

        }catch (Exception e) {
            log.error("图像匹配出错", e);
        }

        return bestMatch;

    }


    /**
     * 多尺度模板匹配核心逻辑：遍历缩放比例，找到最佳匹配
     * @param big 源图像（大图，屏幕截图）
     * @param small 模板图像（小图）
     * @param startScale 最小缩放比例
     * @param endScale 最大缩放比例
     * @param step 缩放步长
     * @param threshold 匹配度阈值
     * @return 最佳匹配结果（MatchResult对象），无匹配则返回null
     */
    private static MatchResult findBestMatch(Mat big, Mat small, double startScale, double endScale, double step, double threshold) {

        /* ---------- 新增：统一为彩色图 CV_8UC3 ---------- */
        // 确保图像类型一致（推荐转为灰度图）
        if (big.type() != small.type()) {

            // 统一转换为3通道 BGR
            if (big.channels() != 3) {
                Imgproc.cvtColor(big, big, Imgproc.COLOR_BGRA2BGR);
            }
            if (small.channels() != 3) {
                Imgproc.cvtColor(small, small, Imgproc.COLOR_BGRA2BGR);
            }

            // log.info("统一转换后通道数source:"+source.channels());
            // log.info("统一转换后通道数template:"+template.channels());
        }
        /* -------------------------------------------------- */

        MatchResult bestResult = null;
        double bestScore = -1; // 初始最佳匹配度（0~1，-1表示未找到有效匹配）

        // 跳过：若模板原始尺寸已大于源图像，直接返回null
        if (small.cols() > big.cols() || small.rows() > big.rows()) {
            return null;
        }

        // 遍历所有缩放比例（从startScale到endScale，步长为step）
        for (double scale = startScale; scale <= endScale; scale += step) {
            // 1. 按当前比例缩放模板
            Mat scaledTemplate = new Mat();
            Size scaledSize = new Size(small.cols() * scale, small.rows() * scale);
            // INTER_AREA：缩放算法（适合缩小图像，保持清晰度）
            Imgproc.resize(small, scaledTemplate, scaledSize, 0, 0, Imgproc.INTER_AREA);

            // 跳过：若缩放后的模板大于源图像，无需匹配
            if (scaledTemplate.cols() > big.cols() || scaledTemplate.rows() > big.rows()) {
                continue;
            }

            // 2. 执行模板匹配（TM_CCOEFF_NORMED：归一化相关系数匹配，结果0~1，1表示完全匹配）
            Mat matchResultMat = new Mat();
            Imgproc.matchTemplate(big, scaledTemplate, matchResultMat, Imgproc.TM_CCOEFF_NORMED);

            // 3. 提取当前比例下的最佳匹配点（最大值和位置）
            Core.MinMaxLocResult minMaxLoc = Core.minMaxLoc(matchResultMat);
            double currentScore = minMaxLoc.maxVal; // 当前比例下的最佳匹配度
            Point currentLoc = minMaxLoc.maxLoc;    // 当前比例下的最佳匹配位置（左上角）

            // 4. 更新全局最佳匹配结果（需同时满足：匹配度高于当前最佳 + 高于阈值）
            if (currentScore > bestScore && currentScore >= threshold) {
                bestScore = currentScore;

                // 计算各个点坐标
                Point startPoint = new Point(currentLoc.x, currentLoc.y);
                Point endPoint = new Point(
                        currentLoc.x + scaledTemplate.cols(),
                        currentLoc.y + scaledTemplate.rows()
                );
                Point centerPoint = new Point(
                        startPoint.x + scaledTemplate.cols() / 2.0,
                        startPoint.y + scaledTemplate.rows() / 2.0
                );

                bestResult = new MatchResult(
                        currentScore,
                        startPoint,
                        endPoint,
                        centerPoint,
                        scaledTemplate.cols(),
                        scaledTemplate.rows(),
                        scale
                );

            }
        }

        return bestResult;
    }
    
    
}
